/**
 * Copyright (c) 2018-2022, NXOS Development Team
 * SPDX-License-Identifier: Apache-2.0
 *
 * Contains: IPC
 *
 * Change Logs:
 * Date           Author            Notes
 * 2023-07-23     kangjinci           Init
 */

#pragma once

#ifdef CONFIG_NX_FILE_MAX_FD
#define NX_FILE_MAX_FD 32
#else
#define NX_FILE_MAX_FD (32)
#endif

#include <nxos/atomic.h>
#include <nxos/fs.h>
#include <nxos/list.h>
#include <nxos/defines.h>
#include <nxos/types.h>

enum NX_FileNodeFlag
{
    NX_FILE_NODE_FLAG_NONE,
    NX_FILE_NODE_FLAG_ROOT,
};

enum NX_FileNodeType
{
    NX_FILE_NODE_TYPE_UNK,
    NX_FILE_NODE_TYPE_DIR,
    NX_FILE_NODE_TYPE_REG,
};
/**
 * todo: 添加address_space概念，优化文件读写速度。
 */
typedef struct NX_FileNode
{
    NX_List link;
    struct NX_MountDesc *mount;
    NX_Atomic refcnt;
    char path[NX_FILE_MAX_PATH];
    enum NX_FileNodeFlag flags;
    enum NX_FileNodeType type;
    NX_Solt lock;
	NX_Solt rdlock;
	NX_Solt wrlock;
    NX_U32 ctime;
    NX_U32 atime;
    NX_U32 mtime;
    NX_U32 mode;
    NX_Size size;
    void *data;
} NX_FileNode;

typedef struct NX_FileDesc
{
    NX_Solt lock;
    struct NX_FileNode *node;
    NX_Offset offset;
    NX_U32 flags;
} NX_FileDesc;

typedef struct NX_FileTable
{
    struct NX_FileDesc file[NX_FILE_MAX_FD];
    NX_Solt file_lock;
} NX_FileTable;

void NX_FileTableInit(NX_FileTable *ft);
NX_FileTable *NX_FileTableGetDefault(void);

enum
{
    NX_MOUNT_RW = (0x0 << 0),
    NX_MOUNT_RO = (0x1 << 0),
    NX_MOUNT_MASK = (0x1 << 0),
};

typedef struct NX_MountDesc
{
    NX_List link;
    struct NX_FileSystem *fs;
    // void * dev;
    NX_Solt dev;
    char path[NX_FILE_MAX_PATH];
    NX_U32 flags;
    NX_Atomic refcnt;
    struct NX_FileNode *root;
    struct NX_FileNode *covered;
    NX_Solt lock;
    void *data;
} NX_MountDesc;

typedef struct NX_FileSystem
{
    NX_List list;
    const char *name;

    NX_Error (*mount)(NX_MountDesc *, const char *);
    NX_Error (*unmount)(NX_MountDesc *);
    NX_Error (*mountSync)(NX_MountDesc *);
    NX_Error (*getNode)(NX_MountDesc *, NX_FileNode *);
    NX_Error (*putNode)(NX_MountDesc *, NX_FileNode *);

    NX_U64 (*read)
    (NX_FileNode *, NX_I64, void *, NX_U64, NX_Error *outErr);
    NX_U64 (*write)
    (NX_FileNode *, NX_I64, void *, NX_U64, NX_Error *outErr);
    NX_Error (*ioctl)(NX_FileNode *, NX_U32, void *);
    NX_Error (*truncate)(NX_FileNode *, NX_I64);
    NX_Error (*sync)(NX_FileNode *);
    NX_Error (*readDir)(NX_FileNode *, NX_I64, NX_Dirent *);
    NX_Error (*lookup)(NX_FileNode *, const char *, NX_FileNode *);
    NX_Error (*create)(NX_FileNode *, const char *, NX_U32);
    NX_Error (*delete)(NX_FileNode *, NX_FileNode *, const char *);
    NX_Error (*rename)(NX_FileNode *, const char *, NX_FileNode *, NX_FileNode *, const char *);
    NX_Error (*createDir)(NX_FileNode *, const char *, NX_U32);
    NX_Error (*deleteDir)(NX_FileNode *, NX_FileNode *, const char *);
    NX_Error (*setMode)(NX_FileNode *, NX_U32);
} NX_FileSystem;

NX_FileSystem *NX_FileSystemSearch(const char *name);
NX_Error NX_FileSystemRegister(NX_FileSystem *fs);
NX_Error NX_FileSystemUnregister(NX_FileSystem *fs);
NX_MountDesc *NX_MountGetByIndex(int index);
int NX_MountGetCount(void);
NX_Error NX_PathBuildAbs(const char *path, char *absPath);
